package multimedia.model.quantize;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;

import multimedia.model.ModifiedImage;
import multimedia.model.PixelCoordinate;
import multimedia.model.colorspace.ColorspaceUtil;
import multimedia.model.colorspace.YIQ;
import multimedia.util.ProjectConstants;

/**
 * 
 * @author ricky
 *
 */
public class MedianCut {
	    private ModifiedImage image;
	    private PixelCoordinate pixMap;
	    private int Y_min, I_min, Q_min, Y_max, I_max, Q_max;
	    private int Y[][];
	    private int I[][];
	    private int Q[][];

	    public MedianCut (ModifiedImage pic)
	    {
	        this.image = pic;
//	        image.getImagePixelHolder().setRgbVector( ColorspaceUtil.ConvertToYIQ( image.getImagePixelHolder().getRgbVector() ) );
	        pixMap = image.getImagePixelHolder();
	        Y_min = 0;
	        I_min = -151;
	        Q_min = -133;
	        Y_max = 255;
	        I_max = 151;
	        Q_max = 133;
	        Y = new int[255][2];
	    	I = new int[302][2];
	    	Q = new int[266][2];
	    }
	    
	    public void MedianCutAlgorithm()
	    {
	    	int Y_bin[] = new int[65];
	    	Y_bin[0] = Y_min;
	    	Y_bin[64] = Y_max;
	    	
	    	int I_bin[] = new int[65];
	    	I_bin[0] = I_min;
	    	I_bin[64] = I_max;
	    	
	    	int Q_bin[] = new int[65];
	    	Q_bin[0] = Q_min;
	    	Q_bin[64] = Q_max;
	    	
	    	for (int i = 0; i < Y_max; i++)
	    	{
	    		Y[i][0] = 0;
	    	}
	    	for (int i = 0; i < (I_max - I_min); i++)
	    	{
	    		I[i][0] = 0;
	    	}
	    	for (int i = 0; i < (Q_max - Q_min); i++)
	    	{
	    		Q[i][0] = 0;
	    	}
	    	
	    	for ( int y = 0; y < image.getImageSize().height; y++ )
	    	{
	    		for ( int x = 0; x < image.getImageSize().width; x++ )
	    		{
	    			YIQ currentPixel = new YIQ(pixMap.getPixelAt(x,y).getFirstComponent(),pixMap.getPixelAt(x,y).getSecondComponent(),pixMap.getPixelAt(x,y).getThirdComponent());
	    			int y_comp = (int) currentPixel.y;
	    			int i_comp = (int) currentPixel.i + I_max;
	    			int q_comp = (int) currentPixel.q + Q_max;
//	    			System.out.println(y_comp + "   " + (i_comp - I_max) + "   " + (q_comp - Q_max));
	    			Y[y_comp][0]++;
	    			I[i_comp][0]++;
	    			Q[q_comp][0]++;
	    			
	    			
	    		}
	    	}
	    	
	    	
	    	//Divides bins respect to Y
	    	int y_sum = 0;
	    	for (int i = 0; i < Y_max; i++)
	    	{
	    		y_sum += Y[i][0];
	    		Y[i][1] = y_sum;
	    	}
	    	int y_control = y_sum / 64;
	    	int y_index_holder = 0;
	    	int y_bin_index = 1;
	    	for (int i = 0; i < Y_max; i++)
	    	{
	    		if (Y[i][1] >= y_control + Y[y_index_holder][1])
	    		{
	    			if (y_bin_index != 63)
	    			{
	    				y_index_holder = i;
	    				Y_bin[y_bin_index] = i;
	    			}
	    			if (y_bin_index < 63)
	    			{
	    				y_bin_index++;
	    			}
	    		}
	    	}
	    	if (Y_bin[63] == 0)
	    	{
	    		int y_temp = 63;
	    		while (Y_bin[y_temp] == 0)
	    		{
	    			y_temp--;
	    		}
	    		int y_idiff = 63 - y_temp;
	    		int y_ndiff = Y_bin[64] - Y_bin[y_temp];
	    		int y_mult = y_ndiff / y_idiff;
	    		while (y_temp < 64)
	    		{
	    			Y_bin[y_temp] = Y_bin[y_temp - 1] + y_mult;
	    			y_temp++;
	    		}
	    		
	    	}
	    	if (Y_bin[63] > Y_bin[64])
	    	{
	    		Y_bin[63] = Y_bin[64] - 1;
	    	}
	    	
	    	
	    	//Divides bins respect to I
	    	int i_sum = 0;
	    	for (int i = 0; i < (I_max - I_min); i++)
	    	{
	    		i_sum += I[i][0];
	    		I[i][1] = i_sum;
	    	}
	    	int i_control = i_sum / 64;
	    	int i_index_holder = 0;
	    	int i_bin_index = 1;
	    	for (int i = 0; i < (I_max - I_min); i++)
	    	{
	    		if (I[i][1] >= i_control + I[i_index_holder][1])
	    		{
	    			if (i_bin_index != 63)
	    			{
	    				i_index_holder = i;
	    				I_bin[i_bin_index] = (i - I_max);
	    			}
	    			if (i_bin_index < 63)
	    			{
	    				i_bin_index++;
	    			}
	    		}
	    	}
	    	if (I_bin[63] == 0)
	    	{
	    		int i_temp = 63;
	    		while (I_bin[i_temp] == 0)
	    		{
	    			i_temp--;
	    		}
	    		int i_idiff = 63 - i_temp;
	    		int i_ndiff = I_bin[64] - I_bin[i_temp];
	    		int i_mult = i_ndiff / i_idiff;
	    		while (i_temp < 64)
	    		{
	    			I_bin[i_temp] = I_bin[i_temp - 1] + i_mult;
	    			i_temp++;
	    		}
	    		
	    	}
	    	if (I_bin[63] > I_bin[64])
	    	{
	    		I_bin[63] = I_bin[64] - 1;
	    	}
	    	
	    	
	    	//Divides bins respect to Q
	    	int q_sum = 0;
	    	for (int i = 0; i < (Q_max - Q_min); i++)
	    	{
	    		q_sum += Q[i][0];
	    		Q[i][1] = q_sum;
	    	}
	    	int q_control = q_sum / 64;
	    	int q_index_holder = 0;
	    	int q_bin_index = 1;
	    	for (int i = 0; i < (Q_max - Q_min); i++)
	    	{
	    		if (Q[i][1] >= q_control + Q[q_index_holder][1])
	    		{
	    			if (q_bin_index != 63)
	    			{
	    				q_index_holder = i;
	    				Q_bin[q_bin_index] = (i - Q_max);
	    			}
	    			if (q_bin_index < 63)
	    			{
	    				q_bin_index++;
	    			}
	    		}
	    	}
	    	if (Q_bin[63] == 0)
	    	{
	    		int q_temp = 63;
	    		while (Q_bin[q_temp] == 0)
	    		{
	    			q_temp--;
	    		}
	    		int q_idiff = 63 - q_temp;
	    		int q_ndiff = Q_bin[64] - Q_bin[q_temp];
	    		int q_mult = q_ndiff / q_idiff;
	    		while (q_temp < 64)
	    		{
	    			Q_bin[q_temp] = Q_bin[q_temp - 1] + q_mult;
	    			q_temp++;
	    		}
	    		
	    	}
	    	if (Q_bin[63] > Q_bin[64])
	    	{
	    		Q_bin[63] = Q_bin[64] - 1;
	    	}
	    	
	    	
	    	//Write file
	    	try
            {
                FileWriter outstream = new FileWriter( ProjectConstants.IMAGE_DB + "histogramSpecification.txt");
                BufferedWriter out = new BufferedWriter(outstream);
                String output = Y_bin[0] + "/" + I_bin[0] + "/" + Q_bin[0] + "/" + Y_bin[1] + "/" + I_bin[1] + "/" + Q_bin[1];
                out.write(output + "\n");
                int y_temp, i_temp, q_temp;
                for (int i = 1; i < 64; i++)
                {
                	out.write("/");
                	y_temp = Y_bin[i] + 1;
                	i_temp = I_bin[i] + 1;
                	q_temp = Q_bin[i] + 1;
                	output = y_temp + "/" + i_temp + "/" + q_temp + "/" + Y_bin[i+1] + "/" + I_bin[i+1] + "/" + Q_bin[i+1];
                	out.write(output + "\n");
                }
                out.close();
            } catch ( IOException e )
            {
                e.printStackTrace();
            }

	    	
	    }

	}
